/*
* File: jquery.flexisel.js
* Version: 2.1.0
* Description: Responsive carousel jQuery plugin
* Author: 9bit Studios
* Copyright 2016, 9bit Studios
* http://www.9bitstudios.com
* Free to use and abuse under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
/* =========================================================================
*
* Creative-Tim Modifications:
* - line 112 and 115 we added Material Icons chevron_left and chevron_right
* ==========================================================================
*/
(function($) {
$.fn.flexisel = function(options) {
var defaults = $.extend({
visibleItems: 4,
itemsToScroll: 3,
animationSpeed: 400,
infinite: true,
navigationTargetSelector: null,
autoPlay: {
enable: false,
interval: 5000,
pauseOnHover: true
},
responsiveBreakpoints: {
portrait: {
changePoint: 480,
visibleItems: 1,
itemsToScroll: 1
},
landscape: {
changePoint: 640,
visibleItems: 2,
itemsToScroll: 2
},
tablet: {
changePoint: 768,
visibleItems: 3,
itemsToScroll: 3
}
}
}, options);
/******************************
Private Variables
*******************************/
var object = $(this);
var settings = $.extend(defaults, options);
var itemsWidth;
var canNavigate = true;
var itemCount;
var itemsVisible = settings.visibleItems;
var itemsToScroll = settings.itemsToScroll;
var responsivePoints = [];
var resizeTimeout;
var autoPlayInterval;
/******************************
Public Methods
*******************************/
var methods = {
init: function() {
return this.each(function() {
methods.appendHTML();
methods.setEventHandlers();
methods.initializeItems();
});
},
/******************************
Initialize Items
*******************************/
initializeItems: function() {
var obj = settings.responsiveBreakpoints;
for (var i in obj) {
responsivePoints.push(obj[i]);
}
responsivePoints.sort(function(a, b) {
return a.changePoint - b.changePoint;
});
var childSet = object.children();
itemsWidth = methods.getCurrentItemWidth();
itemCount = childSet.length;
childSet.width(itemsWidth);
object.css({
'left': -itemsWidth * (itemsVisible + 1)
});
object.fadeIn();
$(window).trigger('resize');
},
/******************************
Append HTML
*******************************/
appendHTML: function() {
object.addClass("nbs-flexisel-ul");
object.wrap("
");
object.find("li").addClass("nbs-flexisel-item");
if (settings.navigationTargetSelector && $(settings.navigationTargetSelector).length > 0) {
$("chevron_left
chevron_right
").appendTo(settings.navigationTargetSelector);
} else {
settings.navigationTargetSelector = object.parent();
$("chevron_left
chevron_right
").insertAfter(object);
}
if (settings.infinite) {
var childSet = object.children();
var cloneContentBefore = childSet.clone();
var cloneContentAfter = childSet.clone();
object.prepend(cloneContentBefore);
object.append(cloneContentAfter);
}
},
/******************************
Set Event Handlers
*******************************/
setEventHandlers: function() {
var childSet = object.children();
$(window).on("resize", function(event) {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function() {
methods.calculateDisplay();
itemsWidth = methods.getCurrentItemWidth();
childSet.width(itemsWidth);
if (settings.infinite) {
object.css({
'left': -itemsWidth * Math.floor(childSet.length / 2)
});
} else {
methods.clearDisabled();
$(settings.navigationTargetSelector).find(".nbs-flexisel-nav-left").addClass('disabled');
object.css({
'left': 0
});
}
}, 100);
});
$(settings.navigationTargetSelector).find(".nbs-flexisel-nav-left").on("click", function(event) {
methods.scroll(true);
});
$(settings.navigationTargetSelector).find(".nbs-flexisel-nav-right").on("click", function(event) {
methods.scroll(false);
});
if (settings.autoPlay.enable) {
methods.setAutoplayInterval();
if (settings.autoPlay.pauseOnHover === true) {
object.on({
mouseenter: function() {
canNavigate = false;
},
mouseleave: function() {
canNavigate = true;
}
});
}
}
object[0].addEventListener('touchstart', methods.touchHandler.handleTouchStart, false);
object[0].addEventListener('touchmove', methods.touchHandler.handleTouchMove, false);
},
/******************************
Calculate Display
*******************************/
calculateDisplay: function() {
var contentWidth = $('html').width();
var largestCustom = responsivePoints[responsivePoints.length - 1].changePoint; // sorted array
for (var i in responsivePoints) {
if (contentWidth >= largestCustom) { // set to default if width greater than largest custom responsiveBreakpoint
itemsVisible = settings.visibleItems;
itemsToScroll = settings.itemsToScroll;
break;
} else { // determine custom responsiveBreakpoint to use
if (contentWidth < responsivePoints[i].changePoint) {
itemsVisible = responsivePoints[i].visibleItems;
itemsToScroll = responsivePoints[i].itemsToScroll;
break;
} else {
continue;
}
}
}
},
/******************************
Scroll
*******************************/
scroll: function(reverse) {
if (typeof reverse === 'undefined') {
reverse = true
}
if (canNavigate == true) {
canNavigate = false;
itemsWidth = methods.getCurrentItemWidth();
if (settings.autoPlay.enable) {
clearInterval(autoPlayInterval);
}
if (!settings.infinite) {
var scrollDistance = itemsWidth * itemsToScroll;
if (reverse) {
object.animate({
'left': methods.calculateNonInfiniteLeftScroll(scrollDistance)
}, settings.animationSpeed, function() {
canNavigate = true;
});
} else {
object.animate({
'left': methods.calculateNonInfiniteRightScroll(scrollDistance)
}, settings.animationSpeed, function() {
canNavigate = true;
});
}
} else {
object.animate({
'left': reverse ? "+=" + itemsWidth * itemsToScroll : "-=" + itemsWidth * itemsToScroll
}, settings.animationSpeed, function() {
canNavigate = true;
if (reverse) {
methods.offsetItemsToBeginning(itemsToScroll);
} else {
methods.offsetItemsToEnd(itemsToScroll);
}
methods.offsetSliderPosition(reverse);
});
}
if (settings.autoPlay.enable) {
methods.setAutoplayInterval();
}
}
},
touchHandler: {
xDown: null,
yDown: null,
handleTouchStart: function(evt) {
this.xDown = evt.touches[0].clientX;
this.yDown = evt.touches[0].clientY;
},
handleTouchMove: function(evt) {
if (!this.xDown || !this.yDown) {
return;
}
var xUp = evt.touches[0].clientX;
var yUp = evt.touches[0].clientY;
var xDiff = this.xDown - xUp;
var yDiff = this.yDown - yUp;
// only comparing xDiff
// compare which is greater against yDiff to determine whether left/right or up/down e.g. if (Math.abs( xDiff ) > Math.abs( yDiff ))
if (Math.abs(xDiff) > 0) {
if (xDiff > 0) {
// swipe left
methods.scroll(false);
} else {
//swipe right
methods.scroll(true);
}
}
/* reset values */
this.xDown = null;
this.yDown = null;
canNavigate = true;
}
},
/******************************
Utility Functions
*******************************/
getCurrentItemWidth: function() {
return (object.parent().width()) / itemsVisible;
},
offsetItemsToBeginning: function(number) {
if (typeof number === 'undefined') {
number = 1
}
for (var i = 0; i < number; i++) {
object.children().last().insertBefore(object.children().first());
}
},
offsetItemsToEnd: function(number) {
if (typeof number === 'undefined') {
number = 1
}
for (var i = 0; i < number; i++) {
object.children().first().insertAfter(object.children().last());
}
},
offsetSliderPosition: function(reverse) {
var left = parseInt(object.css('left').replace('px', ''));
if (reverse) {
left = left - itemsWidth * itemsToScroll;
} else {
left = left + itemsWidth * itemsToScroll;
}
object.css({
'left': left
});
},
getOffsetPosition: function() {
return parseInt(object.css('left').replace('px', ''));
},
calculateNonInfiniteLeftScroll: function(toScroll) {
methods.clearDisabled();
if (methods.getOffsetPosition() + toScroll >= 0) {
$(settings.navigationTargetSelector).find(".nbs-flexisel-nav-left").addClass('disabled');
return 0;
} else {
return methods.getOffsetPosition() + toScroll;
}
},
calculateNonInfiniteRightScroll: function(toScroll) {
methods.clearDisabled();
var negativeOffsetLimit = (itemCount * itemsWidth) - (itemsVisible * itemsWidth);
if (methods.getOffsetPosition() - toScroll <= -negativeOffsetLimit) {
$(settings.navigationTargetSelector).find(".nbs-flexisel-nav-right").addClass('disabled');
return -negativeOffsetLimit;
} else {
return methods.getOffsetPosition() - toScroll;
}
},
setAutoplayInterval: function() {
autoPlayInterval = setInterval(function() {
if (canNavigate) {
methods.scroll(false);
}
}, settings.autoPlay.interval);
},
clearDisabled: function() {
var parent = $(settings.navigationTargetSelector);
parent.find(".nbs-flexisel-nav-left").removeClass('disabled');
parent.find(".nbs-flexisel-nav-right").removeClass('disabled');
}
};
if (methods[options]) { // $("#element").pluginName('methodName', 'arg1', 'arg2');
return methods[options].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof options === 'object' || !options) { // $("#element").pluginName({ option: 1, option:2 });
return methods.init.apply(this);
} else {
$.error('Method "' + method + '" does not exist in flexisel plugin!');
}
};
})(jQuery);